package com.seeyon.apps.sphr.kit;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.seeyon.ctp.common.AppContext;
import com.seeyon.ctp.common.log.CtpLogFactory;
import org.apache.commons.logging.Log;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

public class HttpKit {
    private static final Log log = CtpLogFactory.getLog(HttpKit.class);

    private static final String userName = AppContext.getSystemProperty("oa.userName");
    private static final String password = AppContext.getSystemProperty("oa.password");

    private static PoolingHttpClientConnectionManager cm;
    /* 分隔符 */
    public static final String FILE_BOUNDARY = "-----";

    /**
     * 初始化HttpClient连接池
     * 该方法确保连接池仅被初始化一次，避免重复初始化
     */
    private static void init() {
        // 检查连接管理器是否尚未初始化
        if (cm == null) {
            // 创建连接管理器实例
            cm = new PoolingHttpClientConnectionManager();
            // 设置整个连接池最大连接数为50
            cm.setMaxTotal(50);
            // 设置每路由最大连接数为5
            cm.setDefaultMaxPerRoute(5);
        }
    }


    /**
     * 发送POST请求
     *
     * @param url     请求的URL
     * @param headers 请求的头部参数
     * @param json    请求的JSON数据
     * @return 返回请求结果
     * @throws Exception 异常信息
     */
    public static String post(String url, Map<String, Object> headers, String json) throws Exception {
        // 创建一个HttpGet对象，并指定请求的URL
        HttpPost httpPost = new HttpPost(url);

        // 如果headers集合不为空
        if (!headers.isEmpty()) {
            // 遍历headers集合中的键值对
            for (Map.Entry<String, Object> param : headers.entrySet()) {
                // 向httpPost对象添加请求头
                httpPost.addHeader(param.getKey(), String.valueOf(param.getValue()));
            }
        }
        if (!"".equals(json)) {
            // 创建一个StringEntity对象，并指定实体的内容和编码格式
            StringEntity entity = new StringEntity(json, "UTF-8");
            // 设置StringEntity对象的内容编码格式为"utf-8"
            entity.setContentEncoding("utf-8");
            // 设置StringEntity对象的Content-Type为"application/json"
            entity.setContentType("application/json");

            // 将StringEntity对象设置为httpPost对象的实体
            httpPost.setEntity(entity);
        }

        // 调用getResult方法发送httpPost请求并返回结果
        return getResult(httpPost);

    }

    /**
     * 发起POST请求进行OCR识别
     *
     * @param url 请求的URL地址
     * @param headers 请求的头信息，用于身份验证等
     * @param json 请求体内容，采用JSON格式
     * @return 返回OCR识别的结果，格式为字符串
     * @throws Exception 抛出异常，当网络请求失败或解析错误时
     */
    public static String postOcr(String url, Map<String, Object> headers, String json) throws Exception {
        // 创建一个HttpPost对象，并指定请求的URL
        HttpPost httpPost = new HttpPost(url);

        // 如果headers集合不为空
        if (!headers.isEmpty()) {
            // 遍历headers集合中的键值对
            for (Map.Entry<String, Object> param : headers.entrySet()) {
                // 向httpPost对象添加请求头
                httpPost.addHeader(param.getKey(), String.valueOf(param.getValue()));
            }
        }
        // 如果json字符串不为空
        if (!"".equals(json)) {
            // 创建一个StringEntity对象，并指定实体的内容和编码格式
            StringEntity entity = new StringEntity(json, "UTF-8");
            // 设置StringEntity对象的内容编码格式为"utf-8"
            entity.setContentEncoding("utf-8");
            // 设置StringEntity对象的Content-Type为"application/json"
            entity.setContentType("application/x-www-form-urlencoded");

            // 将StringEntity对象设置为httpPost对象的实体
            httpPost.setEntity(entity);
        }

        // 调用getResult方法发送httpPost请求并返回结果
        return getResult(httpPost);
    }

    /**
     * 向指定URL发送HttpGet请求，并获取返回结果
     *
     * @param url     发送请求的URL
     * @param headers 请求头参数，键值对形式
     * @return 返回请求结果
     * @throws Exception 发生异常时抛出
     */
    public static String get(String url, Map<String, Object> headers) throws Exception {
        // 创建一个HttpGet对象并传入url参数
        HttpGet httpGet = new HttpGet(url);
        // 如果headers参数不为空
        if (!headers.isEmpty()) {
            // 遍历headers参数的每个键值对
            for (Map.Entry<String, Object> param : headers.entrySet()) {
                // 向httpGet对象添加Header参数，键为param的键，值为param的值的字符串形式
                httpGet.addHeader(param.getKey(), String.valueOf(param.getValue()));
            }
        }
        // 调用getResult方法并返回结果
        return getResult(httpGet);
    }


    /**
     * 处理Http请求
     *
     * @param request HTTP请求对象
     * @return 请求结果
     * @throws Exception 抛出异常
     */
    private static String getResult(HttpRequestBase request) throws Exception {
        CloseableHttpClient httpClient = getHttpClient();
        CloseableHttpResponse response = httpClient.execute(request);
        HttpEntity entity = response.getEntity();
        if (entity != null) {
            String result = EntityUtils.toString(entity, "UTF-8");//主数据接口 乱码 加响应编码
            response.close();
            return result;
        }
        return "";
    }


    /**
     * 获取Token
     *
     * @param loginName 用户名
     * @param tokenUrl  获取Token的URL
     * @return 获取到的Token
     * @throws Exception 异常
     */
    public static String getToken(String loginName, String tokenUrl) throws Exception {
        // 创建一个存储参数的Map对象
        Map<String, Object> tokenMap = new HashMap<String, Object>();
        // 将参数放入Map对象中
        tokenMap.put("userName", userName);
        tokenMap.put("loginName", loginName);
        tokenMap.put("password", password);
        // 将Map对象转换为JSON格式的字符串
        String tokenJson = JSON.toJSONString(tokenMap);
        // 调用post方法请求URL获取结果
        String token_result = post(tokenUrl, new HashMap<String, Object>(), tokenJson);
        // 创建一个空字符串
        String tokenId = "";
        // 尝试解析JSON字符串
        try {
            // 将JSON字符串解析为JSONObject对象
            JSONObject token_obj = JSONObject.parseObject(token_result);
            // 从JSONObject对象中获取"id"字段的值，并将其转换为字符串
            tokenId = StrKit.str(token_obj.get("id"));
        } catch (JSONException e) {
            // JSON解析异常时捕获并处理
            log.error("获取token信息失败:", e);
        }
        // 返回获取到的Token
        return tokenId;
    }


    /**
     * 上传文件到指定路径
     *
     * @param pathUrl 路径URL
     * @param file    要上传的文件
     * @return 上传结果
     */
    public static String uploadFile(String pathUrl, File file) {
        try {
            // 创建URL对象，并传入路径URL
            URL preUrl = new URL(pathUrl);
            // 打开URL连接，并将其转换为HttpURLConnection类型
            HttpURLConnection hc = (HttpURLConnection) preUrl.openConnection();
            // 设置请求输出
            hc.setDoOutput(true);
            // 关闭缓存
            hc.setUseCaches(false);
            // 设置请求头部属性
            hc.setRequestProperty("contentType", "charset=utf-8");
            // 设置请求方法为POST
            hc.setRequestMethod("POST");
            // 设置请求头部属性
            hc.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + FILE_BOUNDARY);
            // 创建DataOutputStream对象，用于向连接输出数据
            DataOutputStream dos = new DataOutputStream(hc.getOutputStream());
            // 将getStartData方法返回的数据写入连接
            dos.write(getStartData(file));
            // 创建BufferedInputStream对象，传入文件对象，用于从文件中读取数据
            BufferedInputStream input = new BufferedInputStream(new FileInputStream(file));
            // 定义变量data
            int data = 0;
            // 循环读取输入流中的数据，并将其写入连接
            while ((data = input.read()) != -1) {
                dos.write(data);
            }
            // 将结束标志写入连接
            dos.write(("\r\n--" + FILE_BOUNDARY + "--\r\n").getBytes("UTF-8"));
            // 刷新输出流
            dos.flush();
            // 关闭输出流
            dos.close();
            // 创建StringBuffer对象，用于存储从连接的输入流中读取的数据
            StringBuffer sb = new StringBuffer();
            // 创建InputStream对象，用于从连接中读取数据
            InputStream is = hc.getInputStream();
            // 定义变量ch
            int ch;
            // 循环读取输入流中的数据，并将其添加到StringBuffer对象中
            while ((ch = is.read()) != -1) {
                sb.append((char) ch);
            }
            // 如果输入流不为空，关闭输入流
            if (is != null) {
                is.close();
            }
            // 如果文件输入流不为空，关闭文件输入流
            if (input != null) {
                input.close();
            }
            // 将StringBuffer对象转换为字符串，并返回
            return sb.toString();
        } catch (Exception e) {
            log.error("上传文件失败:", e);
        }
        return null;
    }


    /**
     * 生成文件上传请求的起始数据
     * 此方法用于创建一个符合HTTP协议的文件上传请求的起始部分，包括边界标记、文件名和内容类型
     *
     * @param file 要上传的文件对象
     * @return 字节数组，包含构造的请求起始数据
     * @throws Exception 如果文件名包含非法字符或编码转换失败，则可能抛出此异常
     */
    private static byte[] getStartData(File file) throws Exception {
        // 初始化一个字符串缓冲区，用于构建请求的起始部分
        StringBuffer sb = new StringBuffer();

        // 附加文件边界标记到请求起始部分
        sb.append("--");
        sb.append(FILE_BOUNDARY);
        sb.append("\r\n");

        // 构建并附加包含文件名称的Content-Disposition头信息到请求起始部分
        sb.append("Content-Disposition: form-data; \r\n name=\"1\"; filename=\""
                + file.getName() + "\"\r\n");

        // 附加Content-Type头信息到请求起始部分，指定文件的MIME类型为PNG图像
        sb.append("Content-Type: image/png\r\n\r\n");

        // 将构建的字符串转换为UTF-8编码的字节数组并返回
        return sb.toString().getBytes("UTF-8");
    }


    /**
     * 通过连接池获取HttpClient
     *
     * @return 返回通过连接池获取的HttpClient
     */
    private static CloseableHttpClient getHttpClient() {
        // 初始化
        init();
        // 创建一个基本的Cookie存储对象
        BasicCookieStore cookieStore = new BasicCookieStore();
        // 创建一个HttpClient对象，并设置默认的Cookie存储对象、连接管理器
        return HttpClients.custom().setDefaultCookieStore(cookieStore).setConnectionManager(cm).build();

    }


}
